/*
SDL2_wip.c: Some basic geometric primatives written using SDL2's 
RenderGeometry function

Inspired by the work by:
Copyright (C) 2012-2014  Andreas Schiffler
Additions for BBC BASIC (C) 2016-2020 Richard Russell

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.

Andreas Schiffler -- aschiffler at ferzkopp dot net
Richard Russell -- richard at rtrussell dot co dot uk
Avon -- avon61002 at g mail dot com

*/

#include "SDL2_wip.h"
#include <math.h>
#include <stdio.h>

#define CAP_BUTT 0
#define CAP_SQUARE 1
#define CAP_ROUND 2

#define JOIN_MITER 0
#define JOIN_BEVEL 1
#define JOIN_ROUND 2

int
point (SDL_Renderer *renderer, float x, float y, Uint8 r, Uint8 g, Uint8 b,
       Uint8 a)
{
  int result = 0;
  if (a != 255)
    {
      result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
    }
  result |= SDL_SetRenderDrawColor (renderer, r, g, b, a);
  result |= SDL_RenderDrawPointF (renderer, x, y);
  return 0;
}

int
points (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points,
        Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  SDL_FPoint *points = (SDL_FPoint *)malloc (sizeof (SDL_FPoint) * num_points);
  if (points == NULL)
    {
      return -1;
    }
  for (int i = 0; i < num_points; i++)
    {
      points[i].x = vx[i];
      points[i].y = vy[i];
    }

  int result = 0;
  if (a != 255)
    {
      result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
    }

  result |= SDL_SetRenderDrawColor (renderer, r, g, b, a);
  result |= SDL_RenderDrawPointsF (renderer, points, num_points);
  free (points);
  return result;
}

int
pointsFromVertices (SDL_Renderer *renderer, SDL_Vertex *v, Sint16 num_vertices)
{
  int result = 0;
  for (int i = 0; i < num_vertices; i++)
    {
      SDL_FPoint p = v[i].position;
      SDL_Color c = v[i].color;

      result |= SDL_SetRenderDrawColor (renderer, c.r, c.g, c.b, c.a);
      result |= SDL_RenderDrawPointF (renderer, p.x, p.y);
    }
  return result;
}

int
lineRaw (SDL_Renderer *renderer, float x1, float y1, float x2, float y2,
         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{

  int result = 0;
  if (a != 255)
    {
      result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
    }
  result |= SDL_SetRenderDrawColor (renderer, r, g, b, a);
  result |= SDL_RenderDrawLineF (renderer, x1, y1, x2, y2);
  return result;
}

int
linesRaw (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points)
{
  /* TODO */
  if (num_points % 2 != 0)
    {
      return 1;
    }
  return -1;
}

int
rectRaw (SDL_Renderer *renderer, float x1, float y1, float x2, float y2,
         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  SDL_FRect rect;
  rect.x = x1;
  rect.y = y1;
  rect.w = x2 - x1;
  rect.h = y2 - y1;

  int result = 0;
  if (a != 255)
    {
      result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
    }
  result |= SDL_SetRenderDrawColor (renderer, r, g, b, a);
  result |= SDL_RenderDrawRectF (renderer, &rect);
  return result;
}

int
rectsRaw (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points)
{
  /* TODO */
  if (num_points % 2 != 0)
    {
      return 1;
    }
  return -1;
}

int
filledRectRaw (SDL_Renderer *renderer, float x1, float y1, float x2, float y2,
               Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  SDL_FRect rect;
  rect.x = x1;
  rect.y = y1;
  rect.w = x2 - x1;
  rect.h = y2 - y1;

  int result = 0;
  if (a != 255)
    {
      result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
    }
  result |= SDL_SetRenderDrawColor (renderer, r, g, b, a);
  result |= SDL_RenderFillRectF (renderer, &rect);
  return result;
}

int
filledRectsRaw (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points,
                Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  /* TODO */
  if (num_points % 2 != 0)
    {
      return 1;
    }
  return -1;
}

// Abstracted Shape Functions

int
hLine (SDL_Renderer *renderer, float x1, float y, float x2, float thickness,
       Uint8 cap_type, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  /* TODO error checking */
  int result = 0;
  result |= filledRectRaw (renderer, x1, y - thickness, x2, y + thickness, r, g,
                           b, a);
  return result;
}

int
vLine (SDL_Renderer *renderer, float x, float y1, float y2, float thickness,
       Uint8 cap_type, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  /* TODO error checking */
  int result = 0;
  result |= filledRectRaw (renderer, x - thickness, y1, x + thickness, y2, r, g,
                           b, a);
  return result;
}

// Tessellated Line Segment with 2 triangles with option segment caps
// Reference:
// https://web.archive.org/web/20190614093605/https://forum.libcinder.org/topic/smooth-thick-lines-using-geometry-shader
int
line (SDL_Renderer *renderer, float x1, float y1, float x2, float y2,
      float thickness, Uint8 cap_type, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
  /* TODO input check and check for hLine and vLine */
  // TODO handle caps
  float half_thick = thickness / 2.0;
  float dx = x2 - x1;
  float dy = y2 - y1;
  float mag = sqrt ((dx * dx) + (dy * dy));
  float nx_normalized = -dy / mag;
  float ny_normalized = dx / mag;

  float p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y;

  float nx = half_thick * nx_normalized;
  float ny = half_thick * ny_normalized;

  p1x = x1 - nx;
  p1y = y1 - ny;

  p2x = x1 + nx;
  p2y = y1 + ny;

  p3x = x2 + nx;
  p3y = y2 + ny;

  p4x = x2 - nx;
  p4y = y2 - ny;

  const SDL_Vertex quadVerticies[4]
      = { { { p1x, p1y }, { r, g, b, a }, { 0.f, 0.f } },
          { { p2x, p2y }, { r, g, b, a }, { 0.f, 0.f } },
          { { p3x, p3y }, { r, g, b, a }, { 0.f, 0.f } },
          { { p4x, p4y }, { r, g, b, a }, { 0.f, 0.f } } };

  const int tmp_indicies[6] = { 0, 1, 2, 0, 3, 2 };

  int result = 0;
  result |= SDL_SetRenderDrawBlendMode (renderer, SDL_BLENDMODE_BLEND);
  result
      |= SDL_RenderGeometry (renderer, NULL, quadVerticies, 4, tmp_indicies, 6);
  return result;
}

// Finds the normal vector of point (x1,y1)
// given line x1y1 -> x2y2 and a thickness
SDL_FPoint
_thickNormal (float x1, float y1, float x2, float y2, float thickness)
{
  float half_thick = thickness / 2.0;
  float dx1 = x2 - x1;
  float dy1 = y2 - y1;
  float mag1 = sqrt ((dx1 * dx1) + (dy1 * dy1));
  float nx_normalized = -dy1 / mag1;
  float ny_normalized = dx1 / mag1;

  float nx = nx_normalized * half_thick;
  float ny = ny_normalized * half_thick;

  SDL_FPoint result = { nx, ny };

  return result;
}

// Generates Miter points for a given point (x2,y2),
// based on two control points: (x1,y1) & (x3,y3)
// Reference Diagram:
// https://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation
// wrt the diagram, we are generating points m and -m
SDL_FPoint
_polylineGen (float x1, float y1, float x2, float y2, float x3, float y3,
              float thickness, Uint8 joint_type)
{
  // TODO handle joint types and start/end caps
  float half_thick = thickness / 2.0;
  float dx1 = x2 - x1;
  float dy1 = y2 - y1;
  float mag1 = sqrt ((dx1 * dx1) + (dy1 * dy1));
  float nx_normalized = -dy1 / mag1;
  float ny_normalized = dx1 / mag1;

  float dx2 = x3 - x2;
  float dy2 = y3 - y2;
  float mag2 = sqrt ((dx2 * dx2) + (dy2 * dy2));

  float tx = (dx2 / mag2) + (dx1 / mag1);
  float ty = (dy2 / mag2) + (dy1 / mag1);
  float t_mag = sqrt ((tx * tx) + (ty * ty));

  float tx_normalized = tx / t_mag;
  float ty_normalized = ty / t_mag;

  float mx_normalized = -ty_normalized;
  float my_normalized = tx_normalized;

  float m_mag
      = half_thick
        / ((mx_normalized * nx_normalized) + (my_normalized * ny_normalized));

  float mx = m_mag * mx_normalized;
  float my = m_mag * my_normalized;

  // finding angle between two lines to determine where to put join
  float det = ((-dx1 * dy2) - (-dx2 * dy1));
  float dot = ((-dx1 * dx2) + (-dy1 * dy2));

  float theta = atan2 (det, dot);

  SDL_FPoint m = { mx, my };

  return m;
}

// Tessellated Polyline
int
polyline (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points,
          float thickness, Uint8 joint_type, Uint8 cap_type, Uint8 r, Uint8 g,
          Uint8 b, Uint8 a)
{
  /* TODO */
  if (num_points < 3)
    {
      return 1;
    }
  if (joint_type == 0)
    {
      int num_vertices = 2 * num_points;
      SDL_Vertex *vertices
          = (SDL_Vertex *)malloc (sizeof (SDL_Vertex) * num_vertices);
      if (vertices == NULL)
        return -1;

      int num_indices = 6 * (num_points - 1);
      int *indices = (int *)malloc (sizeof (int) * num_indices);
      if (indices == NULL)
        return -1;

      SDL_FPoint n_prime = _thickNormal (vx[0], vy[0], vx[1], vy[1], thickness);

      SDL_FPoint n = { vx[0] + n_prime.x, vy[0] + n_prime.y };
      SDL_FPoint minus_n = { vx[0] - n_prime.x, vy[0] - n_prime.y };

      SDL_Vertex nv = { n, { 255, g, b, a }, { 0.f, 0.f } };
      SDL_Vertex minus_nv = { minus_n, { r, 255, b, a }, { 0.f, 0.f } };

      vertices[0] = nv;
      vertices[1] = minus_nv;

      for (int i = 0; i < num_points - 2; i++)
        {
          SDL_FPoint m_prime
              = _polylineGen (vx[i], vy[i], vx[i + 1], vy[i + 1], vx[i + 2],
                              vy[i + 2], thickness, 0);
          SDL_FPoint m = { vx[i + 1] + m_prime.x, vy[i + 1] + m_prime.y };
          SDL_FPoint minus_m = { vx[i + 1] - m_prime.x, vy[i + 1] - m_prime.y };

          SDL_Vertex mv = { m, { r, g, 255, a }, { 0.f, 0.f } };
          SDL_Vertex minus_mv = { minus_m, { 255, 255, b, a }, { 0.f, 0.f } };

          vertices[2 * (i + 1)] = mv;
          vertices[2 * (i + 1) + 1] = minus_mv;

          int start_ind = 6 * i;
          int start_vert = 2 * i;

          indices[start_ind] = start_vert;
          indices[start_ind + 1] = start_vert + 1;
          indices[start_ind + 2] = start_vert + 3;
          indices[start_ind + 3] = start_vert;
          indices[start_ind + 4] = start_vert + 2;
          indices[start_ind + 5] = start_vert + 3;
        }

      Sint16 end = num_points - 1;

      SDL_FPoint end_n_prime = _thickNormal (vx[end - 1], vy[end - 1], vx[end],
                                             vy[end], thickness);

      SDL_FPoint end_n = { vx[end] + end_n_prime.x, vy[end] + end_n_prime.y };
      SDL_FPoint end_minus_n
          = { vx[end] - end_n_prime.x, vy[end] - end_n_prime.y };

      SDL_Vertex end_nv = { end_n, { 255, g, b, a }, { 0.f, 0.f } };
      SDL_Vertex end_minus_nv = { end_minus_n, { r, 255, b, a }, { 0.f, 0.f } };

      vertices[num_vertices - 2] = end_nv;
      vertices[num_vertices - 1] = end_minus_nv;

      int ind_end = (6 * (num_points - 1)) - 6;
      indices[ind_end] = num_vertices - 4;
      indices[ind_end + 1] = num_vertices - 3;
      indices[ind_end + 2] = num_vertices - 1;
      indices[ind_end + 3] = num_vertices - 4;
      indices[ind_end + 4] = num_vertices - 2;
      indices[ind_end + 5] = num_vertices - 1;

      if (SDL_RenderGeometry (renderer, NULL, vertices, num_vertices, indices,
                              num_indices))
        {
          printf ("yikes");
        }
      free (vertices);
      free (indices);
    }

  return -1;
}

// Tessellated Polyline that automatically closes the last point to the first
int
closedPolyline (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points,
                float thickness, Uint8 joint_type, Uint8 r, Uint8 g, Uint8 b,
                Uint8 a)
{
  /* TODO */
  if (num_points < 3)
    {
      return 1;
    }
  if (joint_type == 0)
    {
      int num_vertices = 2 * num_points;
      SDL_Vertex *vertices
          = (SDL_Vertex *)malloc (sizeof (SDL_Vertex) * num_vertices);
      if (vertices == NULL)
        return -1;

      int num_indices = 6 * num_points;
      int *indices = (int *)malloc (sizeof (int) * num_indices);
      if (indices == NULL)
        return -1;

      Sint16 end = num_points - 1;
      SDL_FPoint n_prime = _polylineGen (vx[end], vy[end], vx[0], vy[0], vx[1],
                                         vy[1], thickness, joint_type);

      SDL_FPoint n = { vx[0] + n_prime.x, vy[0] + n_prime.y };
      SDL_FPoint minus_n = { vx[0] - n_prime.x, vy[0] - n_prime.y };

      SDL_Vertex nv = { n, { r, g, b, a }, { 0.f, 0.f } };
      SDL_Vertex minus_nv = { minus_n, { r, g, b, a }, { 0.f, 0.f } };

      vertices[0] = nv;
      vertices[1] = minus_nv;

      for (int i = 0; i < num_points - 2; i++)
        {
          SDL_FPoint m_prime
              = _polylineGen (vx[i], vy[i], vx[i + 1], vy[i + 1], vx[i + 2],
                              vy[i + 2], thickness, 0);
          SDL_FPoint m = { vx[i + 1] + m_prime.x, vy[i + 1] + m_prime.y };
          SDL_FPoint minus_m = { vx[i + 1] - m_prime.x, vy[i + 1] - m_prime.y };

          SDL_Vertex mv = { m, { r, g, b, a }, { 0.f, 0.f } };
          SDL_Vertex minus_mv = { minus_m, { r, g, b, a }, { 0.f, 0.f } };

          vertices[2 * (i + 1)] = mv;
          vertices[2 * (i + 1) + 1] = minus_mv;

          int start_ind = 6 * i;
          int start_vert = 2 * i;

          indices[start_ind] = start_vert;
          indices[start_ind + 1] = start_vert + 1;
          indices[start_ind + 2] = start_vert + 3;
          indices[start_ind + 3] = start_vert;
          indices[start_ind + 4] = start_vert + 2;
          indices[start_ind + 5] = start_vert + 3;
        }

      SDL_FPoint end_n_prime
          = _polylineGen (vx[end - 1], vy[end - 1], vx[end], vy[end], vx[0],
                          vy[0], thickness, joint_type);

      SDL_FPoint end_n = { vx[end] + end_n_prime.x, vy[end] + end_n_prime.y };
      SDL_FPoint end_minus_n
          = { vx[end] - end_n_prime.x, vy[end] - end_n_prime.y };

      SDL_Vertex end_nv = { end_n, { r, g, b, a }, { 0.f, 0.f } };
      SDL_Vertex end_minus_nv = { end_minus_n, { r, g, b, a }, { 0.f, 0.f } };

      vertices[num_vertices - 2] = end_nv;
      vertices[num_vertices - 1] = end_minus_nv;

      int ind_end = (6 * (num_points - 1)) - 6;
      indices[ind_end] = num_vertices - 4;
      indices[ind_end + 1] = num_vertices - 3;
      indices[ind_end + 2] = num_vertices - 1;
      indices[ind_end + 3] = num_vertices - 4;
      indices[ind_end + 4] = num_vertices - 2;
      indices[ind_end + 5] = num_vertices - 1;

      ind_end = num_indices - 6;
      indices[ind_end] = num_vertices - 2;
      indices[ind_end + 1] = num_vertices - 1;
      indices[ind_end + 2] = 0;
      indices[ind_end + 3] = num_vertices - 1;
      indices[ind_end + 4] = 0;
      indices[ind_end + 5] = 1;

      if (SDL_RenderGeometry (renderer, NULL, vertices, num_vertices, indices,
                              num_indices))
        {
          printf ("yikes");
        }
      free (vertices);
      free (indices);
    }

  return -1;
}

// Axis-Aligned Rect
int
aaRect (SDL_Renderer *renderer, float x1, float y1, float x2, float y2,
        float stroke_thickness, Uint8 joint_type, Uint8 stroke_r,
        Uint8 stroke_g, Uint8 stroke_b, Uint8 stroke_a, Uint8 filled,
        Uint8 fill_r, Uint8 fill_g, Uint8 fill_b, Uint8 fill_a)
{
  /* TODO handle fancy joints */
  float w = x2 - x1;
  float h = y2 - y1;
  float ht = stroke_thickness / 2;

  if (filled)
    {
      filledRectRaw (renderer, x1, y1, x2, y2, fill_r, fill_g, fill_b, fill_a);
    }

  if (stroke_thickness != 0)
    {
      if (joint_type == 0)
        {
          filledRectRaw (renderer, x1 - ht, y1 - ht, x2 + ht, y1 + ht, stroke_r,
                         stroke_g, stroke_b, stroke_a);
          filledRectRaw (renderer, x2 - ht, y1 + ht, x2 + ht, y2 - ht, stroke_r,
                         stroke_g, stroke_b, stroke_a);
          filledRectRaw (renderer, x1 - ht, y2 - ht, x2 + ht, y2 + ht, stroke_r,
                         stroke_g, stroke_b, stroke_a);
          filledRectRaw (renderer, x1 - ht, y1 + ht, x1 + ht, y2 - ht, stroke_r,
                         stroke_g, stroke_b, stroke_a);
        }
      if (joint_type == 1)
        {
          // TODO
        }
      if (joint_type == 2)
        {
          // TODO
        }
    }
  return 0;
}

int
_renderFanPolygon (SDL_Renderer *renderer, float cx, float cy, float *vx,
                   float *vy, Sint16 num_points, Uint8 r, Uint8 g, Uint8 b,
                   Uint8 a)
{
  /* TODO */
  if (num_points < 3)
    return -1;

  int num_vertices = num_points + 1;
  SDL_Vertex *vertices
      = (SDL_Vertex *)malloc (sizeof (SDL_Vertex) * num_vertices);
  if (vertices == NULL)
    return -1;

  SDL_Vertex v0 = { { cx, cy }, { r, g, b, a }, { 0.f, 0.f } };
  SDL_Vertex v1 = { { vx[0], vy[0] }, { r, g, b, a }, { 0.f, 0.f } };

  vertices[0] = v0;
  vertices[1] = v1;

  int num_indices = 3 * (num_points - 1);
  int *indices = (int *)malloc (sizeof (int) * num_indices);
  if (indices == NULL)
    return -1;

  for (int i = 1; i < num_points; i++)
    {
      SDL_Vertex vi = { { vx[i], vy[i] }, { r, g, b, a }, { 0.f, 0.f } };
      vertices[i + 1] = vi;

      int start_ind = 3 * (i - 1);
      indices[start_ind] = 0;
      indices[start_ind + 1] = i;
      indices[start_ind + 2] = i + 1;
    }

  SDL_RenderGeometry (renderer, NULL, vertices, num_vertices, indices,
                      num_indices);
  return 0;
}

int
_renderClosedFanPolygon (SDL_Renderer *renderer, float cx, float cy, float *vx,
                         float *vy, Sint16 num_points, Uint8 r, Uint8 g,
                         Uint8 b, Uint8 a)
{
  /* TODO */
  if (num_points < 3)
    return -1;

  int num_vertices = num_points + 1;
  SDL_Vertex *vertices
      = (SDL_Vertex *)malloc (sizeof (SDL_Vertex) * num_vertices);
  if (vertices == NULL)
    return -1;

  SDL_Vertex v0 = { { cx, cy }, { r, g, b, a }, { 0.f, 0.f } };
  SDL_Vertex v1 = { { vx[0], vy[0] }, { r, g, b, a }, { 0.f, 0.f } };

  vertices[0] = v0;
  vertices[1] = v1;

  int num_indices = 3 * num_points;
  int *indices = (int *)malloc (sizeof (int) * num_indices);
  if (indices == NULL)
    return -1;

  for (int i = 1; i < num_points; i++)
    {
      SDL_Vertex vi = { { vx[i], vy[i] }, { r, g, b, a }, { 0.f, 0.f } };
      vertices[i + 1] = vi;

      int start_ind = 3 * (i - 1);
      indices[start_ind] = 0;
      indices[start_ind + 1] = i;
      indices[start_ind + 2] = i + 1;
    }
  int end_ind = 3 * (num_points - 1);
  indices[end_ind] = 0;
  indices[end_ind + 1] = num_points;
  indices[end_ind + 2] = 1;

  SDL_RenderGeometry (renderer, NULL, vertices, num_vertices, indices,
                      num_indices);
  return 0;
}

int
regularPolygon (SDL_Renderer *renderer, float cx, float cy, float rad,
                Sint16 num_sides, float stroke_thickness, Uint8 joint_type,
                Uint8 stroke_r, Uint8 stroke_g, Uint8 stroke_b, Uint8 stroke_a,
                Uint8 filled, Uint8 fill_r, Uint8 fill_g, Uint8 fill_b,
                Uint8 fill_a)
{
  /* TODO error checking */

  float *vx = (float *)malloc (sizeof (float) * num_sides);
  float *vy = (float *)malloc (sizeof (float) * num_sides);

  for (int i = 0; i < num_sides; i++)
    {
      vx[i] = (rad * cos ((2 * M_PI / num_sides) * i)) + cx;
      vy[i] = rad * sin ((2 * M_PI / num_sides) * i) + cy;
    }

  if (filled)
    {
      _renderClosedFanPolygon (renderer, cx, cy, vx, vy, num_sides, fill_r,
                               fill_g, fill_b, fill_a);
    }
  if (stroke_thickness)
    {
      closedPolyline (renderer, vx, vy, num_sides, stroke_thickness, 0,
                      stroke_r, stroke_g, stroke_b, stroke_a);
    }
  free (vx);
  free (vy);
  return -1;
}

// Convex Polygon rendered using Fan Triangulation
// Reference: https://en.wikipedia.org/wiki/Fan_triangulation
int
convexPolygon (SDL_Renderer *renderer, float *vx, float *vy, Sint16 num_points,
               float stroke_thickness, Uint8 joint_type, Uint8 stroke_r,
               Uint8 stroke_g, Uint8 stroke_b, Uint8 stroke_a, Uint8 filled,
               Uint8 fill_r, Uint8 fill_g, Uint8 fill_b, Uint8 fill_a)
{
  /* TODO */
  return -1;
}
